<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      div {
        position: absolute;
        left: 0;
        width: 100px;
        height: 100px;
        background-color: red;
        opacity: 1;
      }
      #topDiv {
        top: 200px;
      }
      #bottomDiv {
        top: 400px;
      }
    </style>
  </head>
  <body>
    <div id="topDiv"></div>
    <div id="bottomDiv"></div>

    <script>
      const topDivEl = document.querySelector("#topDiv");
      const bottomDivEl = document.querySelector("#bottomDiv");

      topDivEl.onclick = function () {
        console.log("first");
        startMove(
          this,
          {
            width: 400,
            height: 400,
            left: 200,
            top: 300,
            opacity: 0.5,
          },
          function () {
            console.log("执行完成了");
          }
        );
      };

      function getStyle(dom, attr) {
        if (window.getComputedStyle) {
          return window.getComputedStyle(dom)[attr];
        } else {
          return dom.currentStyle[attr];
        }
      }

      function startMove(domEl, attrObj, cb) {
        clearInterval(domEl.timer);
        domEl.timer = setInterval(function () {
          let iSpeed = null,
            iCur = null;
          let bStop = true;

          for (const attr in attrObj) {
            const target =
              attr === "opacity" ? attrObj[attr] * 100 : attrObj[attr];
            const isNeedBig = attr === "opacity";
            const unix = isNeedBig ? "" : "px";
            iCur = isNeedBig
              ? parseFloat(getStyle(domEl, attr)) * 100
              : parseInt(getStyle(domEl, attr));

            iSpeed = (target - iCur) / 7;
            iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);

            domEl.style[attr] = isNeedBig
              ? (iCur + iSpeed) / 100
              : iCur + iSpeed + unix;

            if (iCur !== target) {
              bStop = false;
            }
          }

          if (bStop) {
            clearInterval(domEl.timer);
            typeof cb === "function" && cb();
          }
        }, 30);
      }
    </script>
  </body>
</html>
